package hu.myai.gui.widgets.model;

import java.util.ArrayList;
import java.util.Collection;

public class Scalar implements IScalar {
    private int index;
    private int depth;
    private double[] data;
    private int[] colorData;
    private int[] styleData;
    private Collection<IScalarListener> listeners;

    public Scalar(int depth) {
        this.index = 0;
        this.depth = Math.max(depth, 1);
        this.data = new double[this.depth];
        this.colorData = new int[this.depth];
        this.styleData = new int[this.depth];
        listeners = new ArrayList<IScalarListener>();
    }

    @Override
    public int getDepth() {
        return depth;
    }

    @Override
    public double getValue(int time) {
        time = Math.max(Math.min(time, depth - 1), 0);
        return data[(index + depth - time) % depth];
    }

    @Override
    public void setDepth(int newDepth) {
        newDepth = Math.max(newDepth, 1);
        double[] newData = new double[newDepth];
        int[] newColorData = new int[newDepth];
        int[] newStyleData = new int[newDepth];

        int minDepth = Math.min(this.depth, newDepth);
        for (int i = 0; i < minDepth; i++) {
            newData[i] = getValue(minDepth - 1 - i);
            newColorData[i] = getColor(minDepth - 1 - i);
        }
        this.index = minDepth - 1;
        int oldDepth = this.depth;
        this.depth = newDepth;
        this.data = newData;
        this.colorData = newColorData;
        this.styleData = newStyleData;
        fireDepthChanged(oldDepth, newDepth);
    }

    @Override
    public void setValue(double newValue, int color, int style) {
        double oldValue = data[index];
        index = (index + 1) % depth;
        data[index] = newValue;
        colorData[index] = color;
        styleData[index] = style;
        fireValueChanged(oldValue, newValue);
    }

    @Override
    public double getMin() {
        double min = Double.POSITIVE_INFINITY;

        for (double d : data) {
            min = Math.min(min, d);
        }

        return min;
    }

    @Override
    public double getMax() {
        double max = Double.NEGATIVE_INFINITY;

        for (double d : data) {
            max = Math.max(max, d);
        }

        return max;
    }
    
    public int getColor(int time){
        time = Math.max(Math.min(time, depth - 1), 0);
        return colorData[(index + depth - time) % depth];
    }
    
    public int getStyle(int time){
        time = Math.max(Math.min(time, depth - 1), 0);
        return styleData[(index + depth - time) % depth];
    }

    @Override
    public void addScalarListener(IScalarListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeScalarListener(IScalarListener listener) {
        listeners.remove(listener);
    }

    private void fireValueChanged(double oldValue, double newValue) {
        for (IScalarListener l : listeners) {
            l.valueChanged(this, oldValue, newValue);
        }
    }

    private void fireDepthChanged(int oldDepth, int newDepth) {
        for (IScalarListener l : listeners) {
            l.depthChanged(this, oldDepth, newDepth);
        }
    }

}
